import { Injectable, NestMiddleware } from '@nestjs/common';
import { UserActivityLogService } from '../modules/log/services/user-activity-log.service';
import { Request, Response } from 'express';
import { HttpMethod } from '../modules/log/constants/user-activity-log.constant';

@Injectable()
export class UserActivityLoggerMiddleware implements NestMiddleware {
  constructor(private readonly userActivityLogService: UserActivityLogService) {}

  /**
   * 请求中间件处理
   * @param req 请求体
   * @param res 返回体
   * @param next next函数
   */
  async use(req: Request, res: Response, next: any) {
    const startTime = Date.now();

    const ip = req.headers['x-forwarded-for']?.toString() || req.socket.remoteAddress;

    const url = req.path;
    const method = (req.method as unknown) as HttpMethod;

    const paramsDataList = [];
    if (req.body && JSON.stringify(req.body) !== '{}') paramsDataList.push('body:' + JSON.stringify(req.body));
    if (req.params && JSON.stringify(req.params) !== '{}') paramsDataList.push('params:' + JSON.stringify(req.params));
    if (req.query && JSON.stringify(req.query) !== '{}') paramsDataList.push('query:' + JSON.stringify(req.query));

    const reqMessage = paramsDataList.length > 0 ? paramsDataList.join(' AND ') : 'no data';

    const finishHandler = () => {
      const resCode = res.statusCode;
      const operator = req.user && 'uuid' in req.user ? req.user.uuid : null;

      switch (Math.floor(resCode / 100)) {
        case 2:
          this.userActivityLogService.info(method, url, reqMessage, resCode, res.statusMessage, Date.now() - startTime, ip, operator);
          break;
        case 3:
          if (resCode == 304) this.userActivityLogService.info(method, url, reqMessage, resCode, res.statusMessage, Date.now() - startTime, ip, operator);
          else this.userActivityLogService.warn(method, url, reqMessage, resCode, res.statusMessage, Date.now() - startTime, ip, operator);
          break;
        case 4:
          this.userActivityLogService.error(method, url, reqMessage, resCode, res.statusMessage, Date.now() - startTime, ip, operator);
          break;
        case 5:
          this.userActivityLogService.fatal(method, url, reqMessage, resCode, res.statusMessage, Date.now() - startTime, ip, operator);
          break;
        default:
          this.userActivityLogService.fatal(method, url, reqMessage, resCode, res.statusMessage, Date.now() - startTime, ip, operator);
      }
    };

    res.once('finish', finishHandler);
    next();
  }
}
